#include <iostream>
#include <functional>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "log.hpp"

using namespace LogModule;

typedef std::function<std::string(const std::string&)> func_t;

class UdpServer
{
public:
    UdpServer(uint16_t port, func_t func)
        //:_ip(ip)
        :_port(port)
        , _func(func)
    {}

    void Init()
    {
        //1. 创建套接字
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(_sockfd == -1)
        {
            LOG(LogLevel::FATAL) << "socket error";
            exit(1);
        }
        LOG(LogLevel::DEBUG) << "socket access : " << _sockfd;

        //2. 绑定端口号和ip
        struct sockaddr_in local;
        bzero(&local, sizeof local);
        local.sin_family = AF_INET; // 表示网络通信
        local.sin_port = htons(_port); // 端口号
        //local.sin_addr.s_addr = inet_addr(_ip.c_str()); // ip地址
        local.sin_addr.s_addr = INADDR_ANY;

        //绑定
        int n = bind(_sockfd, (struct sockaddr*)&local, sizeof local);
        if(n == -1)
        {
            LOG(LogLevel::FATAL) << "bind error";
            exit(1);
        }
        LOG(LogLevel::DEBUG) << "bind access : " << _sockfd;
    }

    void Start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            //1. 收到客户端的消息
            char buff[1024];
            struct sockaddr_in peer;
            socklen_t len = sizeof peer;
            ssize_t s = recvfrom(_sockfd, buff, sizeof buff - 1, 0, (struct sockaddr*)&peer, &len);
            if(s > 0)
            {
                //收到消息后，打印一下消息发送者
                int peer_port = ntohs(peer.sin_port);
                std::string peer_ip = inet_ntoa(peer.sin_addr); // 将4字节IP转成点分十进制

                buff[s] = '\0';
                LOG(LogLevel::DEBUG) << "[" << peer_ip << ":" << peer_port << "]#" << buff;

                //数据处理
                std::string ret = _func(buff);

                //2. 向客户端发消息 -- 谁发的，就发给谁
                // std::string echo_string = "server echo@";
                // echo_string += buff;
                sendto(_sockfd, ret.c_str(), ret.size(), 0, (struct sockaddr*)&peer, len);
            }
        }
    }
private:
    int _sockfd = -1;
    uint16_t _port; // 端口号
    //std::string _ip; // ip地址
    bool _isrunning = false;

    //数据处理
    func_t _func;
};